package com.trussell.genesis.terrainmanipulation;

/*
* Copyright (c) 2005 MonkeyWorld3d - Monkey World 3d
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Monkey World 3d, MW3D, MonkeyWorld3d, nor the
*    names of its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import com.jme.math.FastMath;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.TexCoords;
import com.jme.scene.TriMesh;
import com.jme.util.geom.BufferUtils;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.TerrainPage;

/**
 * This is a class which will be used to mark the terrain cursor position.
 * I will try to create a circle with some radius.
 *
 * @author ndebruyn
 * Created on May 31, 2005
 */
public class TerrainMarker extends TriMesh {

	private static final long serialVersionUID = 1L;
	private int radialSamples;
	private float radius;
	private float ringWidth;
	private ColorRGBA colorRGBA;
	private Vector3f[] vertex;
	private Vector3f[] normal;
	private ColorRGBA[] color;
	private Vector2f[][] texture;
	private int[] indices;


	public TerrainMarker(String name, int radialSamples, float radius, float ringWidth, ColorRGBA colorRGBA) {
		super(name);

		this.radialSamples = radialSamples;
		this.radius = radius;
		this.ringWidth = ringWidth;
		this.colorRGBA = colorRGBA;

		texture = new Vector2f[1][];
		// allocate vertices
		int quantity = ((radialSamples+1) * 2);
		vertex = new Vector3f[quantity];
		normal = new Vector3f[quantity];
		color = new ColorRGBA[quantity];
		texture[0] = new Vector2f[quantity];

		int indexQuantity = radialSamples * (6);
		indices = new int[indexQuantity];

		setGeometryData();
		setColorData();
		setIndexData();
		this.setLightCombineMode(LightCombineMode.Off);
		this.setTextureCombineMode(TextureCombineMode.Off);

		this.setMode(Mode.Strip);
	}

	private void setGeometryData() {
		// generate geometry
		float f1 = 1.0F / (float)radialSamples;
		int c = 0;
		for (int r=0; r<radialSamples+1; r++) {

			float f2 = FastMath.TWO_PI * (f1 * (float)r);
			if (r == radialSamples) {
				f2 = FastMath.TWO_PI * (f1 * (float)0);
			}
			//Outsize
			float x = radius * FastMath.cos(f2);
			float z = radius * FastMath.sin(f2);
			float y = 0.0F;
			Vector3f vector3f2out = new Vector3f(x, y, z);

			//Insize
			x = (radius-(ringWidth)) * FastMath.cos(f2);
			z = (radius-(ringWidth)) * FastMath.sin(f2);
			y = 0.0F;
			Vector3f vector3f2in = new Vector3f(x, y, z);
			vertex[c] = vector3f2out;
			c++;
			vertex[c] = vector3f2in;
			c++;
		}
		this.setVertexBuffer(BufferUtils.createFloatBuffer(vertex));
		this.setColorBuffer(BufferUtils.createFloatBuffer(color));
		this.setVertexBuffer(BufferUtils.createFloatBuffer(normal));
		this.setTextureCoords(new TexCoords(BufferUtils.createFloatBuffer(texture[0]), 0));
	}

	private void setIndexData() {
		// generate connectivity
	    int c = 0;
	    int t = 0;
		for (; t < indices.length; t=t+3) {
		    indices[t] = c;
		    indices[t+1] = c+1;
		    indices[t+2] = c+2;
		    c++;
		}
		this.setIndexBuffer(BufferUtils.createIntBuffer(indices));
	}

	private void setColorData() {
		for (int x = 0; x < color.length; x++) {
			color[x] = colorRGBA;
		}
		this.setColorBuffer(BufferUtils.createFloatBuffer(color));
	}

    /**
     * We need to update the marker position.
     */
    public void update(Vector3f midPoint, TerrainPage page) {
        setLocalTranslation(midPoint);
        float x = getLocalTranslation().x;
        float y = getLocalTranslation().y;
        float z = getLocalTranslation().z;
        float newY;
        float incrMent = 0.3F;
        float oldY = 0.0F;

        for (int t=0; t<vertex.length; t++) {
            newY = page.getHeight(x+vertex[t].x, z+vertex[t].z);
            //I the value is a NaN set it to be 0.0F
            if (Float.isNaN(newY) || newY > radius+y) {
                vertex[t].y = (oldY-y) + incrMent;
        	} else {
                vertex[t].y = (newY-y) + incrMent;
                oldY = newY;
            }
        }
        reconstruct(vertex, normal, color, texture[0]);
        updateGeometricState(0.0F, true);
    }

    public void update(Vector3f midPoint, TerrainBlock page) {
        setLocalTranslation(midPoint);
        float x = getLocalTranslation().x;
        float y = getLocalTranslation().y;
        float z = getLocalTranslation().z;
        float newY;
        float incrMent = 0.3F;
        float oldY = 0.0F;

        for (int t=0; t<vertex.length; t++) {
            newY = page.getHeight(x+vertex[t].x, z+vertex[t].z);
            //I the value is a NaN set it to be 0.0F
            if (Float.isNaN(newY) || newY > radius+y) {
                vertex[t].y = (oldY-y) + incrMent;
        	} else {
                vertex[t].y = (newY-y) + incrMent;
                oldY = newY;
            }
        }
        reconstruct(vertex, normal, color, texture[0]);
        updateGeometricState(0.0F, true);
    }

    private void reconstruct(Vector3f[] vertex2, Vector3f[] normal2,
			ColorRGBA[] color2, Vector2f[] vector2fs) {
		// TODO Auto-generated method stub
		super.reconstruct(BufferUtils.createFloatBuffer(vertex),
				BufferUtils.createFloatBuffer(normal),
				BufferUtils.createFloatBuffer(color),
				new TexCoords(BufferUtils.createFloatBuffer(texture[0]), 0));
	}

	public void reset(ColorRGBA colorRGBA, float radius) {
        if (colorRGBA != null)
            this.colorRGBA = colorRGBA;

        this.radius = radius;
        setGeometryData();
        setColorData();
        reconstruct(vertex, normal, color, texture[0]);
        updateGeometricState(0.0F, true);
    }
    public float getRadius() {
        return radius;
    }
}